Skip to content

Add comprehensive UI examples to app-crm: FormView, PageSchema, and component composition#669

Merged
hotlong merged 5 commits into
mainfrom
copilot/add-form-view-examples
Feb 13, 2026
Merged

Add comprehensive UI examples to app-crm: FormView, PageSchema, and component composition#669
hotlong merged 5 commits into
mainfrom
copilot/add-form-view-examples

Conversation

Copilot AI commented Feb 13, 2026

Copy link
Copy Markdown
Contributor

Adds comprehensive UI examples to examples/app-crm/src/views/ and examples/app-crm/src/pages/ demonstrating the full expressiveness of ObjectStack's UI metadata protocol. Implements all form layouts, page types, and component compositions referenced in the schemas but previously unexemplified.

Enhanced Component Schemas

component.zod.ts:

  • RecordDetailsProps: Added fields override, enhanced layout options (1-4 columns, auto/custom)
  • RecordHighlightsProps: Added layout orientation (horizontal/vertical)
  • RecordRelatedListProps: Added filter, title, actions, showViewAll
  • New schemas: RecordActivityProps, RecordPathProps, PageAccordionProps, AIChatWindowProps
  • ARIA attributes on all components

FormView Examples (app-crm/src/views/lead.view.ts)

All 6 layout types with advanced field controls:

formViews: {
  // 1. Simple: sectioned forms with collapsible sections
  quick_create: {
    type: 'simple',
    sections: [
      { label: 'Info', collapsible: true, columns: 2, fields: [...] }
    ]
  },
  
  // 2. Tabbed: multi-tab organization
  detail_form: {
    type: 'tabbed',
    sections: [
      { label: 'General', columns: 2, fields: [...] },
      { label: 'Qualification', columns: 2, fields: [...] }
    ]
  },
  
  // 3. Wizard: step-by-step guided process
  lead_conversion_wizard: {
    type: 'wizard',
    sections: [
      { label: 'Step 1: Contact Details', fields: [...] },
      { label: 'Step 2: Company Info', fields: [...] },
      { label: 'Step 3: Qualification', fields: [...] },
      { label: 'Step 4: Review', fields: [...] }
    ]
  },
  
  // 4. Split: master-detail view
  // 5. Drawer: side panel quick edit
  // 6. Modal: dialog-based actions
}

Field-level controls demonstrated:

{
  field: 'state',
  colSpan: 2,                    // Span 2 columns in layout
  dependsOn: 'country',          // Cascading dependency
  visibleOn: 'status != "new"',  // Conditional visibility
  widget: 'star_rating',         // Custom widget override
  required: true,
  readonly: false,
  helpText: 'Select state/province'
}

PageSchema Examples (app-crm/src/pages/)

All 4 page types with component composition:

lead_detail.page.ts (record page):

{
  type: 'record',
  template: 'header-sidebar-main',
  regions: [
    {
      name: 'sidebar',
      components: [
        {
          type: 'record:highlights',
          properties: {
            fields: ['status', 'rating', 'owner', 'email'],
            layout: 'vertical'
          }
        },
        {
          type: 'ai:chat_window',
          properties: { mode: 'sidebar', agentId: 'sales_assistant' },
          visibility: 'status == "qualified"'
        }
      ]
    },
    {
      name: 'main',
      components: [
        {
          type: 'page:tabs',
          properties: {
            items: [
              {
                label: 'Details',
                children: [
                  { type: 'record:details', properties: { columns: '2' } }
                ]
              },
              {
                label: 'Related',
                children: [
                  {
                    type: 'page:accordion',
                    properties: {
                      items: [
                        {
                          label: 'Tasks',
                          children: [
                            {
                              type: 'record:related_list',
                              properties: {
                                objectName: 'task',
                                relationshipField: 'lead_id',
                                columns: ['subject', 'status', 'due_date'],
                                sort: [{ field: 'due_date', order: 'asc' }],
                                filter: [['status', '!=', 'completed']],
                                limit: 10,
                                actions: ['new_task', 'edit']
                              }
                            }
                          ]
                        }
                      ]
                    }
                  }
                ]
              }
            ]
          }
        }
      ]
    }
  ],
  assignedProfiles: ['sales_user', 'sales_manager']
}

Additional page types:

  • home.page.ts: Dashboard-style with KPIs, three-column template
  • app_launcher.page.ts: Application launcher grid
  • utility_bar.page.ts: Floating utility panels

Integration with CRM Example

UI examples are integrated into the existing app-crm example to demonstrate how FormView and PageSchema work within a complete application context:

  • Location: examples/app-crm/src/views/ and examples/app-crm/src/pages/
  • Updated Documentation: Enhanced app-crm/README.md with UI examples section
  • Architecture: Follows the by-type directory layout standard

This approach provides better context by showing how UI components integrate with the comprehensive CRM application including objects, workflows, agents, and security models.

Original prompt

完善 examples ,体现平台能力
FormView(类似 Salesforce Page Layout) — view.zod.ts

6 种表单布局:simple / tabbed / wizard / split / drawer / modal
分区(Section)支持:可折叠、1-4 列布局
字段级控制:readonly / required / hidden / colSpan / visibleOn(条件可见)/ dependsOn(级联)/ 自定义 widget
支持命名多个 formViews,可按场景切换
2. PageSchema(类似 Salesforce Lightning Record Page / FlexiPage) — page.zod.ts

页面类型:record / home / app / utility
基于模板 + 区域(regions)的组件化布局
丰富的组件类型:record:details、record:highlights、record:related_list、page:tabs、page:accordion、ai:chat_window 等
组件级可见性规则(visibility)
按 Profile 分配页面(assignedProfiles)
3. 组件属性 — component.zod.ts

RecordDetailsProps:1-4 列,auto/custom 布局模式
RecordHighlightsProps:1-7 个关键字段高亮
RecordRelatedListProps:关联对象、列、排序、条数

The user has attached the following file paths as relevant context:

  • .github/copilot-instructions.md

Created from VS Code.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@vercel

vercel Bot commented Feb 13, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectstack-play Canceled Canceled Feb 13, 2026 6:25pm
spec Ready Ready Preview, Comment Feb 13, 2026 6:25pm

Request Review

Copilot AI and others added 2 commits February 13, 2026 17:30
… enhanced component properties

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
…ance rating field documentation

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
@hotlong

hotlong commented Feb 13, 2026

Copy link
Copy Markdown
Collaborator

@copilot example应该基于 crm,而不是写新的

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Add examples to showcase platform capabilities in FormView Add comprehensive UI protocol examples: FormView, PageSchema, and component composition Feb 13, 2026
Copilot AI requested a review from hotlong February 13, 2026 17:39
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>

Copilot AI commented Feb 13, 2026

Copy link
Copy Markdown
Contributor Author

@copilot example应该基于 crm,而不是写新的

Done! Moved all UI examples from standalone ui-showcase/ to examples/app-crm/src/views/ and examples/app-crm/src/pages/. Updated CRM README to document the new sections. (commit 8748865)

Copilot AI changed the title Add comprehensive UI protocol examples: FormView, PageSchema, and component composition Add comprehensive UI examples to app-crm: FormView, PageSchema, and component composition Feb 13, 2026
@hotlong
hotlong marked this pull request as ready for review February 13, 2026 17:44
Copilot AI review requested due to automatic review settings February 13, 2026 17:44
@hotlong
hotlong merged commit 9f72062 into main Feb 13, 2026
1 of 3 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds comprehensive UI examples to the examples/app-crm package, demonstrating ObjectStack's full UI metadata protocol capabilities. The changes enhance the component schemas in @objectstack/spec and provide extensive working examples of FormView layouts, PageSchema types, and component composition patterns.

Changes:

  • Enhanced component schemas with detailed properties for RecordDetails, RecordRelatedList, RecordHighlights, and added new schemas for RecordActivity, RecordPath, PageAccordion, and AIChatWindow with ARIA support
  • Added comprehensive FormView examples demonstrating all 6 layout types (simple, tabbed, wizard, split, drawer, modal) with field-level controls
  • Created 4 PageSchema examples showing record detail, home dashboard, app launcher, and utility bar page types
  • Updated app-crm documentation to reflect the new UI examples

Reviewed changes

Copilot reviewed 9 out of 10 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
pnpm-lock.yaml Adds package reference for examples/ui-showcase (non-existent - should be removed)
packages/spec/src/ui/component.zod.ts Enhanced component property schemas with detailed descriptions, ARIA support, and new component types
examples/app-crm/src/views/lead.view.ts Comprehensive FormView examples for all 6 layout types with 5 list view types and field-level controls
examples/app-crm/src/views/index.ts Export file for LeadViews
examples/app-crm/src/pages/lead_detail.page.ts Record page example with highlights, tabs, accordion, and related lists
examples/app-crm/src/pages/home.page.ts Home page example with dashboard layout and KPI highlights
examples/app-crm/src/pages/app_launcher.page.ts App launcher page with grid layout
examples/app-crm/src/pages/utility_bar.page.ts Utility bar page with floating panels
examples/app-crm/src/pages/index.ts Export file for all page examples
examples/app-crm/README.md Documentation updates describing UI examples and their features
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

Comment on lines +282 to +283
label: 'Lead Detail Page',
description: 'Detailed view of lead information with related records and activity',

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid ARIA properties: The AriaPropsSchema defines properties as ariaLabel, ariaDescribedBy, and role, but this code uses label and description. Change label to ariaLabel and either remove description or change it to ariaDescribedBy with a reference to an element ID.

Suggested change
label: 'Lead Detail Page',
description: 'Detailed view of lead information with related records and activity',
ariaLabel: 'Lead Detail Page',
ariaDescribedBy: 'lead_detail_page_description',

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +70
label: 'Utility Bar',
description: 'Quick access utility bar with floating tools and notifications',

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid ARIA properties: The AriaPropsSchema defines properties as ariaLabel, ariaDescribedBy, and role, but this code uses label and description. Change label to ariaLabel and either remove description or change it to ariaDescribedBy with a reference to an element ID.

Suggested change
label: 'Utility Bar',
description: 'Quick access utility bar with floating tools and notifications',
ariaLabel: 'Utility Bar',

Copilot uses AI. Check for mistakes.
Comment on lines +67 to +68
label: 'App Launcher Page',
description: 'Central application launcher for accessing all apps',

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid ARIA properties: The AriaPropsSchema defines properties as ariaLabel, ariaDescribedBy, and role, but this code uses label and description. Change label to ariaLabel and either remove description or change it to ariaDescribedBy with a reference to an element ID.

Suggested change
label: 'App Launcher Page',
description: 'Central application launcher for accessing all apps',
ariaLabel: 'App Launcher Page',

Copilot uses AI. Check for mistakes.
Comment thread pnpm-lock.yaml
Comment on lines +340 to +349
examples/ui-showcase:
dependencies:
'@objectstack/spec':
specifier: workspace:*
version: link:../../packages/spec
devDependencies:
typescript:
specifier: ^5.9.0
version: 5.9.3

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pnpm-lock.yaml adds an entry for examples/ui-showcase package, but this directory does not exist in the repository. The actual UI examples were added to examples/app-crm/src/views/ and examples/app-crm/src/pages/ instead. This lock file entry should be removed as it references a non-existent package.

Suggested change
examples/ui-showcase:
dependencies:
'@objectstack/spec':
specifier: workspace:*
version: link:../../packages/spec
devDependencies:
typescript:
specifier: ^5.9.0
version: 5.9.3

Copilot uses AI. Check for mistakes.
Comment on lines +1 to +3
// Copyright (c) 2025 ObjectStack. Licensed under the Apache-2.0 license.

import { defineView } from '@objectstack/spec/ui';

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The PR description mentions examples/ui-showcase multiple times (e.g., "examples/ui-showcase/src/views/lead.view.ts") but the actual implementation is in examples/app-crm. While the PR title correctly states "Add comprehensive UI examples to app-crm", the description body should be updated to refer to examples/app-crm instead of examples/ui-showcase for consistency.

Copilot uses AI. Check for mistakes.
Comment on lines +140 to +700
sections: [
{
label: 'Contact Information',
collapsible: true,
collapsed: false,
columns: 2, // 2-column layout
fields: [
{
field: 'salutation',
colSpan: 1,
},
{
field: 'first_name',
required: true,
colSpan: 1,
},
{
field: 'last_name',
required: true,
colSpan: 2, // Span both columns
},
'company',
'title',
'email',
'phone',
'mobile',
'website',
],
},
{
label: 'Lead Classification',
collapsible: true,
collapsed: false,
columns: 3, // 3-column layout
fields: [
{
field: 'status',
required: true,
},
{
field: 'rating',
widget: 'star_rating', // Custom widget
},
'lead_source',
'industry',
{
field: 'owner',
required: true,
},
],
},
{
label: 'Company Information',
collapsible: true,
collapsed: true, // Collapsed by default
columns: 2,
fields: [
'annual_revenue',
'number_of_employees',
],
},
{
label: 'Address',
collapsible: true,
collapsed: true,
columns: 2,
fields: [
{
field: 'street',
colSpan: 2, // Full width
},
'city',
'state',
'postal_code',
'country',
],
},
{
label: 'Additional Information',
collapsible: true,
collapsed: true,
columns: 1, // Single column for text areas
fields: [
'description',
'notes',
],
},
{
label: 'Privacy',
collapsible: true,
collapsed: true,
columns: 2,
fields: [
'do_not_call',
'email_opt_out',
],
},
],
},

/**
* Additional Named List Views
*/
listViews: {
/**
* Kanban Board View
*/
kanban_by_status: {
name: 'kanban_by_status',
type: 'kanban',
label: 'Lead Pipeline',
data: {
provider: 'object',
object: 'lead',
},
columns: ['first_name', 'last_name', 'company', 'email'],
kanban: {
groupByField: 'status',
summarizeField: 'annual_revenue',
columns: ['first_name', 'last_name', 'company', 'rating'],
},
navigation: {
mode: 'drawer', // Open in drawer instead of new page
width: '600px',
},
},

/**
* Calendar View
*/
calendar_by_created: {
name: 'calendar_by_created',
type: 'calendar',
label: 'Lead Calendar',
data: {
provider: 'object',
object: 'lead',
},
columns: ['first_name', 'last_name', 'company'],
calendar: {
startDateField: 'created_at',
titleField: 'company',
colorField: 'status',
},
},

/**
* Gallery/Card View
*/
gallery_view: {
name: 'gallery_view',
type: 'gallery',
label: 'Lead Cards',
data: {
provider: 'object',
object: 'lead',
},
columns: ['first_name', 'last_name', 'company', 'email', 'status'],
gallery: {
cardSize: 'medium',
titleField: 'company',
visibleFields: ['first_name', 'last_name', 'email', 'phone', 'status', 'rating'],
},
},

/**
* My Leads - Filtered View
*/
my_leads: {
name: 'my_leads',
type: 'grid',
label: 'My Leads',
data: {
provider: 'object',
object: 'lead',
},
columns: ['first_name', 'last_name', 'company', 'email', 'status', 'rating'],
filter: [
['owner', '=', '{current_user_id}']
],
sort: [
{ field: 'rating', order: 'desc' },
{ field: 'created_at', order: 'desc' }
],
},

/**
* High Priority Leads
*/
high_priority: {
name: 'high_priority',
type: 'grid',
label: 'High Priority',
data: {
provider: 'object',
object: 'lead',
},
columns: ['first_name', 'last_name', 'company', 'email', 'status', 'rating', 'lead_source'],
filter: [
['rating', '>=', 4],
['status', 'in', ['new', 'contacted']]
],
rowColor: {
field: 'rating',
colors: {
'5': '#00AA00',
'4': '#FFA500',
},
},
},
},

/**
* Additional Named Form Views - Demonstrating All 6 Layout Types
*/
formViews: {
/**
* 1. SIMPLE Layout (already shown as default form above)
* Basic sectioned form
*/
quick_create: {
type: 'simple',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'Quick Lead Creation',
columns: 2,
fields: [
{ field: 'first_name', required: true },
{ field: 'last_name', required: true },
{ field: 'company', required: true, colSpan: 2 },
{ field: 'email', required: true },
'phone',
'status',
'owner',
],
},
],
},

/**
* 2. TABBED Layout
* Organize complex forms with tabs
*/
detail_form: {
type: 'tabbed',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'General',
columns: 2,
fields: [
'salutation',
'first_name',
'last_name',
'company',
'title',
'email',
'phone',
'mobile',
],
},
{
label: 'Qualification',
columns: 2,
fields: [
{ field: 'status', required: true },
{ field: 'rating', widget: 'star_rating' },
'lead_source',
'industry',
'annual_revenue',
'number_of_employees',
],
},
{
label: 'Address',
columns: 2,
fields: [
{ field: 'street', colSpan: 2 },
'city',
{
field: 'state',
dependsOn: 'country', // Cascade: country determines available states
},
'postal_code',
'country',
],
},
{
label: 'Details',
columns: 1,
fields: [
'description',
'notes',
'do_not_call',
'email_opt_out',
],
},
],
},

/**
* 3. WIZARD Layout
* Step-by-step guided process
*/
lead_conversion_wizard: {
type: 'wizard',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'Step 1: Contact Details',
columns: 2,
fields: [
{ field: 'first_name', required: true, readonly: true },
{ field: 'last_name', required: true, readonly: true },
{ field: 'email', readonly: true, colSpan: 2 },
'phone',
'mobile',
],
},
{
label: 'Step 2: Company Information',
columns: 2,
fields: [
{ field: 'company', required: true, readonly: true },
'title',
'industry',
'annual_revenue',
'number_of_employees',
'website',
],
},
{
label: 'Step 3: Qualification',
columns: 2,
fields: [
{ field: 'status', required: true },
{ field: 'rating', widget: 'star_rating' },
'lead_source',
{
field: 'owner',
visibleOn: 'rating >= 4', // Conditional visibility
},
],
},
{
label: 'Step 4: Review & Convert',
columns: 1,
fields: [
{
field: 'description',
helpText: 'Review all information before converting to Account and Contact',
},
],
},
],
},

/**
* 4. SPLIT Layout
* Master-detail split view
*/
split_edit: {
type: 'split',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'Primary Information',
columns: 1,
fields: [
'first_name',
'last_name',
'company',
'email',
{ field: 'status', required: true },
'owner',
],
},
{
label: 'Extended Details',
columns: 2,
fields: [
'phone',
'mobile',
'title',
'industry',
'lead_source',
{ field: 'rating', widget: 'star_rating' },
'annual_revenue',
'number_of_employees',
],
},
],
},

/**
* 5. DRAWER Layout
* Side panel form (typically opened from list view)
*/
quick_edit_drawer: {
type: 'drawer',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'Quick Edit',
columns: 1, // Drawers typically use single column
fields: [
{ field: 'first_name', required: true },
{ field: 'last_name', required: true },
'company',
'email',
'phone',
{ field: 'status', required: true },
{ field: 'rating', widget: 'star_rating' },
'lead_source',
{
field: 'owner',
visibleOn: 'status != "new"', // Only show owner after initial contact
},
],
},
],
},

/**
* 6. MODAL Layout
* Dialog-based form for quick actions
*/
status_update_modal: {
type: 'modal',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'Update Lead Status',
columns: 1,
fields: [
{ field: 'first_name', readonly: true },
{ field: 'last_name', readonly: true },
{ field: 'company', readonly: true },
{
field: 'status',
required: true,
helpText: 'Select the new status for this lead',
},
{
field: 'rating',
widget: 'star_rating',
visibleOn: 'status == "qualified"', // Only show rating for qualified leads
},
{
field: 'notes',
placeholder: 'Add notes about this status change',
visibleOn: 'status == "unqualified"', // Require notes for unqualified
},
],
},
],
},

/**
* Advanced Example: Conditional Field Visibility & Dependencies
*/
advanced_conditional: {
type: 'simple',
data: {
provider: 'object',
object: 'lead',
},
sections: [
{
label: 'Lead Information',
columns: 2,
fields: [
'first_name',
'last_name',
'company',
'email',
'status',
'lead_source',
{
field: 'rating',
widget: 'star_rating',
visibleOn: 'status != "new"', // Only show after first contact
},
{
field: 'industry',
dependsOn: 'company', // Industry options depend on company
},
{
field: 'annual_revenue',
visibleOn: 'rating >= 3', // Only for qualified leads
},
{
field: 'number_of_employees',
visibleOn: 'rating >= 3',
},
{
field: 'owner',
required: true,
visibleOn: 'status == "contacted" OR status == "qualified"',
},
{
field: 'notes',
colSpan: 2,
required: true,
visibleOn: 'status == "unqualified"', // Require explanation for unqualified
},
],
},
{
label: 'Address Information',
collapsible: true,
collapsed: true,
columns: 2,
fields: [
{ field: 'street', colSpan: 2 },
'city',
{
field: 'state',
dependsOn: 'country', // Country determines state options
},
'postal_code',
'country',
],
},
{
label: 'Privacy Preferences',
collapsible: true,
collapsed: true,
columns: 2,
fields: [
{
field: 'do_not_call',
helpText: 'Check if this lead has requested not to be called',
},
{
field: 'email_opt_out',
helpText: 'Check if this lead has opted out of email communications',
},
],
},
],
},

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type mismatch throughout file: The FormSectionSchema expects columns to be a string enum ('1', '2', '3', or '4'), but numeric literals are being used consistently (e.g., columns: 2, columns: 3, columns: 1). All columns values in section definitions should be changed to strings: '1', '2', '3', or '4'. This affects approximately 20+ occurrences in this file across all the form view examples.

Copilot uses AI. Check for mistakes.
Comment on lines +186 to +189
label: 'Sales Home Page',
description: 'Sales team home page with metrics, leads, and quick actions',
},
};

Copilot AI Feb 13, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Invalid ARIA properties: The AriaPropsSchema defines properties as ariaLabel, ariaDescribedBy, and role, but this code uses label and description. Change label to ariaLabel and either remove description or change it to ariaDescribedBy with a reference to an element ID.

Suggested change
label: 'Sales Home Page',
description: 'Sales team home page with metrics, leads, and quick actions',
},
};
ariaLabel: 'Sales Home Page',
},
};

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants